#include "CAppendWithCounterTable.h"

#include "CUKeyUValueCalc.h"
#include "CppSQLite3.h"
#include <sstream>
#include <iostream>

int CAppendWithCounterTable::getTableType() const
{
	return TableTypeAppendWithCounter;
}

void CAppendWithCounterTable::setTableConfigure(const CTableConfigurePtr& tableConfigure)
{
	CTableBase::setTableConfigure(tableConfigure);
}

int CAppendWithCounterTable::InitTable()
{
	m_tableConfigure->setTableField(CTableField("uKey", EFieldType::EFieldTypeInt, 0));
	m_tableConfigure->setTableField(CTableField("uCount", EFieldType::EFieldTypeInt, 0));
	m_tableConfigure->setTableField(CTableField("timeStart", EFieldType::EFieldTypeInt, 0));
	m_tableConfigure->setTableField(CTableField("timeEnd", EFieldType::EFieldTypeInt, 0));

	return CTableBase::InitTable();
}

int CAppendWithCounterTable::beforeWriteRecord(CLogRecordPtr logRecord)
{
	// Call base class to handle common fields including UUID
	CTableBase::beforeWriteRecord(logRecord);

	CUKeyUValueCalc calc(this);
	calc.CalculateUKeyUValue(logRecord);

	if (!logRecord->hasField("uKey"))
		logRecord->AddField("uKey", calc.getUKey());

	uint64_t now = getTimestamp();

	if( !logRecord->hasField("timeStart"))
		logRecord->AddField("timeStart", now);
	
	if (!logRecord->hasField("timeEnd"))
		logRecord->AddField("timeEnd", now);

	return 0;
}

int CAppendWithCounterTable::writeRecord(CLogRecordPtr logRecord)
{
	try {
		// Check if we have the required components
		if (!logRecord || !m_tableConfigure || !m_logDatabase) {
			return -1; // Error: missing record, configuration, or database
		}
		
		// Get the database connection
		CppSQLite3DB* db = m_logDatabase->getDatabaseConnection();
		if (!db) {
			return -2; // Error: no database connection
		}
		
		// Get the table name
		std::string tableName = m_tableConfigure->getTableName();
		if (tableName.empty()) {
			return -3; // Error: no table name
		}
		
		// Get uKey from the record
		auto& recordFields = logRecord->GetFields();
		auto uKeyIt = recordFields.find("uKey");
		if (uKeyIt == recordFields.end()) {
			return -4; // Error: uKey field not found
		}
		
		uint64_t uKey = 0;
		const CLogValue& uKeyValue = uKeyIt->second->GetValue();
		if (uKeyValue.type() == typeid(uint64_t)) {
			uKey = boost::get<uint64_t>(uKeyValue);
		} else {
			return -5; // Error: uKey is not a valid integer
		}
		
		// Check if a record with this uKey already exists
		std::stringstream selectSql;
		selectSql << "SELECT uuid, uCount,timeStart FROM " << tableName << " WHERE uKey = ?";
		
		CppSQLite3Statement selectStmt = db->compileStatement(selectSql.str().c_str());
		selectStmt.bind(1, static_cast<sqlite3_int64>(uKey));
		CppSQLite3Query query = selectStmt.execQuery();
		
		if (!query.eof()) {
			// Record exists - get existing uuid and uCount
			std::string existingUuid = query.getStringField("uuid");
			logRecord->AddField("uuid", existingUuid);

			uint64_t startTime = query.getIntField("timeStart");
			if ( startTime )
				logRecord->AddField("timeStart", startTime);
			
			int existingUCount = query.getIntField("uCount");
			query.finalize();
			
			// Delete the old record
			std::stringstream deleteSql;
			deleteSql << "DELETE FROM " << tableName << " WHERE uKey = ?";
			
			CppSQLite3Statement deleteStmt = db->compileStatement(deleteSql.str().c_str());
			deleteStmt.bind(1, static_cast<sqlite3_int64>(uKey));
			deleteStmt.execDML();
			
			// Update uCount and set the existing uuid
			logRecord->AddField("uCount", static_cast<uint64_t>(existingUCount + 1));
			
			
			
			std::cout << "Updated record with uKey " << uKey << ", uCount: " << (existingUCount + 1) << std::endl;
		} else {
			// Record doesn't exist - set uCount to 1
			logRecord->AddField("uCount", static_cast<uint64_t>(1));
			query.finalize();
			std::cout << "Inserted new record with uKey " << uKey << ", uCount: 1" << std::endl;
		}
		
		// Use base class InsertRecord method
		return InsertRecord(logRecord);
		
	} catch (const CppSQLite3Exception& e) {
		// Handle SQLite exceptions
		//std::cout << "SQLite error in writeRecord: " << e.errorMessage() << std::endl;
		return -6; // Error: SQLite exception
	} catch (const std::exception& e) {
		// Handle other exceptions
		std::cout << "General error in writeRecord: " << e.what() << std::endl;
		return -7; // Error: general exception
	}
}

